import re

from django.contrib.auth import login
from django.db import DatabaseError
from django.shortcuts import render, redirect
from django import http
from QQLoginTool.QQtool import OAuthQQ
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import move_cart_cookie_to_redis
from apps.oauth.models import OAuthQQUser, OAuthSinaUser
from apps.oauth.utils import generate_eccess_token, check_access_token
from apps.users.models import User
from libs import sinaweibopy3
from meiduo_mall import settings
from utils.response_code import RETCODE
import logging
logger = logging.getLogger('django')


# 定义一个类, 处理点击QQ图标进入QQ登录页面的业务
class QQAuthURLView(View):

    def get(self, request):
        # next表示从哪个页面进入到的登录页面，将来登录成功后，就自动回到那个页面
        next = request.GET.get('next')


        # 获取QQ登录页面网页数据
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI,
                        state=next)
        # 获取QQ扫码登录页面, 扫码后得到Authorization Code
        login_url = oauth.get_qq_url()
        # 返回拼接好的QQ登录的url
        return http.JsonResponse({'code': RETCODE.OK,
                                  'errmsg': 'OK',
                                  'login_url':login_url})

# 定义一个类, 处理QQ登录成功后的业务
class QQAuthUserView(View):

    def get(self, request):
        # OAuth2.0认证
        code = request.GET.get('code')
        if code is None:
            return http.HttpResponseBadRequest('缺少参数')

        # 通过code获取token
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI,
                        state=next)
        try:
            # 使用code向QQ服务器请求access_token
            access_token = oauth.get_access_token(code)
            # 使用access_token向QQ服务器请求openid
            openid = oauth.get_open_id(access_token)

        except Exception as e:
            logger.error(e)

            return http.HttpResponseBadRequest('OAuth2.0认证失败')

        try:
            oauth_user = OAuthQQUser.objects.get(openid=openid)

        except OAuthQQUser.DoesNotExist:
            # 如果openid没绑定过用户
            # 对openid先进行加密处理
            access_token = generate_eccess_token(openid)
            return render(request, 'oauth_callback.html', context={'access_token':access_token})
        else:
            # 如果openid绑定过用户
            qq_user = oauth_user.user
            login(request, qq_user)
            # 重定向到首页
            response = redirect(reverse('contents:index'))
            # 登陆时用户名写入cookie, 有效期15天
            response.set_cookie('username', qq_user.username, max_age=3600* 24* 15)
            return response


    '''
       openid绑定用户实现
       对获取的手机号进行判断
       如果已存在,就绑定已有的数据信息进行登录
       如果不存在,就新注册一个用户
       '''
    def post(self, request):
        # 接受手机号, 密码, 短信验证码, openid
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        sms_code_client = request.POST.get('sms_code')
        # access_token是加密后的openid
        access_token = request.POST.get('access_token')

        # 校验数据
        # 判断参数是否齐全
        if not all([mobile, password, sms_code_client]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('请输入正确的手机号码')
        # 判断密码是否合格
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseBadRequest('请输入8-20位的密码')
        # 判断短信验证码是否一致
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        if sms_code_server is None:
            return render(request, 'oauth_callback.html', {'sms_code_errmsg': '无效的短信验证码'})
        if sms_code_client != sms_code_server.decode():
            return render(request, 'oauth_callback.html', {'sms_code_errmsg': '输入短信验证码有误'})
        # 判断openid是否有效：错误提示放在sms_code_errmsg位置
        # 线对openid进行解密处理
        openid = check_access_token(access_token)
        if not openid:
            return render(request, 'oauth_callback.html', {'openid_errmsg': '无效的openid'})

        # 保存注册数据
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 如果用户不存在, 新建用户
            user = User.objects.create_user(username=mobile,
                                            password=password,
                                            mobile=mobile)
        else:
            # 如果用户存在, 检查用户密码
            if not user.check_password(password):
                return http.HttpResponseBadRequest('绑定失败')

        # 将用户绑定openid
        try:
            OAuthQQUser.objects.create(openid=openid,
                                       user=user)
        except DatabaseError:
            return http.HttpResponseBadRequest('QQ登录失败')

        # 实现状态保持
        login(request, user)

        # 登录返回首页
        response = redirect(reverse('contents:index'))

        # 登录时用户名写入cookie, 有效期15天
        response.set_cookie('username', user.username, max_age=3600* 24* 15)

        # 登录时合并购物车
        move_cart_cookie_to_redis(request, response, user)

        return response


# 处理进入微博登陆界面
class WeiboAuthURLView(View):

    # next表示从哪个页面进入到的登录页面，将来登录成功后，就自动回到那个页面
    def get(self, request):
        next = request.GET.get('next')

        # 获取微博登录页面网页数据
        clinet = sinaweibopy3.APIClient(
            app_key=settings.WEIBO_CLIENT_ID,
            app_secret=settings.WEIBO_CLIENT_SECRET,
            redirect_uri=settings.WEIBO_REDIRECT_URI,
        )

        # 获取QQ扫码登录页面, 扫码后得到Authorization Code
        login_url = clinet.get_authorize_url()
        # 返回拼接好的QQ登录的url
        return http.JsonResponse({'code': RETCODE.OK,
                                  'errmsg': 'OK',
                                  'login_url':login_url})

# 登陆微博后跳转注册界面
class WeiboAuthUserView(View):

    def get(self, request):
        # OAuth2.0认证
        code = request.GET.get('code')
        if code is None:
            return http.HttpResponseBadRequest('缺少参数')

        # 通过code获取token
        client = sinaweibopy3.APIClient(
            app_key=settings.WEIBO_CLIENT_ID,
            app_secret=settings.WEIBO_CLIENT_SECRET,
            redirect_uri=settings.WEIBO_REDIRECT_URI,
        )
        try:
            # 使用code向微博服务器请求access_token
            access_token = client.request_access_token(code)
            # 使用access_token向微博服务器请求openid
            openid = access_token.uid

            # # 使用code向微博服务器请求access_token
            # result = client.request_access_token(code)
            # access_token = result.access_token
            # # 使用access_token向微博服务器请求openid
            # openid = access_token.uid

        except Exception as e:
            logger.error(e)

            return http.HttpResponseBadRequest('OAuth2.0认证失败')

        try:
            client_user = OAuthSinaUser.objects.get(uid=openid)

        except OAuthSinaUser.DoesNotExist:
            # 如果openid没绑定过用户
            # 对openid先进行加密处理
            access_token = generate_eccess_token(openid)
            return render(request, 'oauth_callback.html', context={'access_token': access_token})

        else:
            # 如果openid绑定过用户
            weibo_user = client_user.user
            login(request, weibo_user)
            # 重定向到首页
            response = redirect(reverse('contents:index'))
            # 登陆时用户名写入cookie, 有效期15天
            response.set_cookie('username', weibo_user.username, max_age=3600 * 24 * 15)
            return response


    '''
       openid绑定用户实现
       对获取的手机号进行判断
       如果已存在,就绑定已有的数据信息进行登录
       如果不存在,就新注册一个用户
    '''
    def post(self, request):
        # 接受手机号, 密码, 短信验证码, openid
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        sms_code_client = request.POST.get('sms_code')
        # access_token是加密后的openid
        access_token = request.POST.get('access_token')

        # 校验数据
        # 判断参数是否齐全
        if not all([mobile, password, sms_code_client]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('请输入正确的手机号码')
        # 判断密码是否合格
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseBadRequest('请输入8-20位的密码')
        # 判断短信验证码是否一致
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        if sms_code_server is None:
            return render(request, 'sina_callback.html', {'sms_code_errmsg': '无效的短信验证码'})
        if sms_code_client != sms_code_server.decode():
            return render(request, 'sina_callback.html', {'sms_code_errmsg': '输入短信验证码有误'})
        # 判断openid是否有效：错误提示放在sms_code_errmsg位置
        # 线对openid进行解密处理
        openid = check_access_token(access_token)
        if not openid:
            return render(request, 'sina_callback.html', {'openid_errmsg': '无效的openid'})

        # 保存注册数据
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 如果用户不存在, 新建用户
            user = User.objects.create_user(username=mobile,
                                            password=password,
                                            mobile=mobile)
        else:
            # 如果用户存在, 检查用户密码
            if not user.check_password(password):
                return http.HttpResponseBadRequest('绑定失败')

        # 将用户绑定openid
        try:
            OAuthSinaUser.objects.create(uid=openid,
                                       user=user)
        except DatabaseError:
            return http.HttpResponseBadRequest('微博登录失败')

        # 实现状态保持
        login(request, user)

        # 登录返回首页
        response = redirect(reverse('contents:index'))

        # 登录时用户名写入cookie, 有效期15天
        response.set_cookie('username', user.username, max_age=3600* 24* 15)

        # 登录时合并购物车
        move_cart_cookie_to_redis(request, response, user)

        return response